package com.pi.core;

import com.baidu.aip.face.AipFace;
import com.pi.entity.SignIn;
import com.pi.mapper.SignInMapper;
import com.pi.utils.GetTimeUtil;
import com.pi4j.util.ExecUtil;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * @author 管俊
 * @version 1.0
 * @date 2023/10/15
 */
@Component
public class startFaceRecognize implements ApplicationRunner {

    //设置百度的一些参数
    public static final String APP_ID = "39487376"; // 设置 APP ID

    public static final String API_KEY = "cAGNapqpp8YRVM8Kr5AABYbL"; // 设置 API Key
    public static final String SECRET_KEY = "l7Zaa5k0UEp8FiKuvo5vyb3eEBtMfO8T"; // 设置 Secret Key
    public static int index = 0; // 照片的序列号

    @Autowired
    SignInMapper signInMapper;


    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 初始化一个 AipFace
        AipFace client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
        // 可选：设置网络连接参数
        client.setConnectionTimeoutInMillis(2000);
        client.setSocketTimeoutInMillis(60000);

        while (true) {
            // 每隔 5 s，进行一次照片的抓取
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            // 调用百度智能云，人脸查找接口
            HashMap<String, Object> options = new HashMap();
            // 匹配阈值，score 低于此阈值的用户信息将不会返回
            options.put("match_threshold", "90");
            // 图片的编码格式
            String imageType = "BASE64";
            // 人脸库的组号
            String groupIdList = "project";

            // 使用 CSI 摄像头，进行人脸照片的抓取
            String fileName = index + ".jpg";
            // 树莓派控制 CSI 摄像头的指令
            try {
                ExecUtil.execute("raspistill -o " + (index++) + ".jpg -t 1000");
            } catch (IOException e) {
                throw new RuntimeException(e);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // 将图片转换成 Base 64 编码
            String image = convertImageToBase64Str(fileName);

            // 调用百度的人脸识别API
            JSONObject res = client.search(image, imageType, groupIdList, options);
            System.out.println("百度智能云人脸识别返回结果res = " + res);
            /**
             * API 接口返回结果的格式：
             * 如果成功，返回结果如下：
             * {
             *     "error_code": 0,
             *     "error_msg": "SUCCESS",
             *     "log_id": 1944499608,
             *     "timestamp": 1698831144,
             *     "cached": 0,
             *     "result": {
             *         "face_token": "e4e5440a5cd95a3c58b3dddf00009e5d",
             *         "user_list": [
             *             {
             *                 "group_id": "project",
             *                 "user_id": "202210131",
             *                 "user_info": "蒋明喆",
             *                 "score": 95.724960327148
             *             }
             *         ]
             *     }
             * }
             * 如果失败，返回结果如下：
             * {
             *     "error_code": 222202,
             *     "error_msg": "pic not has face",
             *     "log_id": 2012699291,
             *     "timestamp": 1698831212,
             *     "cached": 0,
             *     "result": null
             * }
             */
            Map<String, Object> resMap = res.toMap();
            // 搜索成功，对应学生签到成功
            if (resMap.get("error_msg").equals("SUCCESS")) {
                // 从 res 中提取学生的姓名和学号，便于后端的实现
                Object username = ((Map) ((List) ((Map) resMap.get("result")).get("user_list")).get(0)).get("user_info");
                Object userID = ((Map) ((List) ((Map) resMap.get("result")).get("user_list")).get(0)).get("user_id");

                String text = username + "同学，你已经签到成功!";
                System.out.println(text);
                /**
                 * 下面后端部分的逻辑由蒋明哲完成
                 */
                //判断数据库是不是已经插入过此人
                //获取当前的日期
                int Year = GetTimeUtil.getCalendar().get(Calendar.YEAR);
                int Month = GetTimeUtil.getCalendar().get(Calendar.MONTH) + 1;
                int Day = GetTimeUtil.getCalendar().get(Calendar.DATE);
                SignIn signIn = signInMapper.selectStudentIsSignInToday(Year, Month, Day, (String) userID);
                if (signIn == null) {
                    //如果没有插入，创建一个SignIn类
                    SignIn record = new SignIn();
                    record.setStudentId((String) userID);
                    record.setTime(new Date());
                    record.setIsSignIn("是");
                    //通过返回影响的条数，判断是否插入成功
                    int i = signInMapper.insertOneSignIn(record);
                    if (i == 1) {
                        System.out.println("插入成功");
                    } else {
                        System.out.println("插入失败");
                    }
                } else {
                    System.out.println("你已经签到成功了，不用再签了");
                }

            } else {
                // 搜索失败，没有找到对应的学生，签到失败
                System.out.println("抱歉，签到失败！");
            }

        }
    }

    /**
     * 图片转 Base64 字符串
     *
     * @param imageFileName
     * @return
     */
    public String convertImageToBase64Str(String imageFileName) {
        ByteArrayOutputStream baos = null;
        try {
            //获取图片类型
            String suffix = imageFileName.substring(imageFileName.lastIndexOf(".") + 1);
            //构建文件
            File imageFile = new File(imageFileName);
            //通过 ImageIO 把文件读取成 BufferedImage 对象
            BufferedImage bufferedImage = ImageIO.read(imageFile);
            //构建字节数组输出流
            baos = new ByteArrayOutputStream();
            //写入流
            ImageIO.write(bufferedImage, suffix, baos);
            //通过字节数组流获取字节数组
            byte[] bytes = baos.toByteArray();
            //获取JDK8里的编码器Base64.Encoder转为base64字符
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (baos != null) {
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}